package globals
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;
	
	import waveData.LoopData;

	public class TrueLoop extends EventDispatcher
	{
		public static const DATA_REFRESH:String = "dataEvent";
		public static const START_PLAYING:String = "startEvent";
		public static const STOP_PLAYING:String = "stopEvent";
		public static const CHANGE_VOLUME:String = "changeVolEvent";
		
		public static var superLoop:TrueLoop;
		
		public var repeat:Boolean = true;
		private var _name:String;
		private var _parent:TrueLoop;
		private var _volume:Number = 1;
		private var _loopData:LoopData;
		private var _playing:Boolean;
		private var _oneShot:Boolean = false;
		private var _length:int;
		
		private var _startTime:uint;
		private var _tempLoopData:LoopData;
		private var _primitives:Vector.<Primitive>;
		
		public function TrueLoop(parent:TrueLoop = null, loopData:LoopData = null, name:String = "")
		{
			_name = name;
			_primitives = new Vector.<Primitive>();
			_loopData = loopData;
			if (parent != null)
			{
				_parent = parent;
				_parent.addEventListener(TrueLoop.START_PLAYING, play);
				_parent.addEventListener(TrueLoop.STOP_PLAYING, stop);
			}
			else
			{
				superLoop = this;
			}
		}
		
		public function play(event:Event = null):void
		{
			if (_playing) return void;
			_startTime = getTimer();
			_tempLoopData = _loopData.clone();
			_tempLoopData.position = 0;
			TopLevel.root.addEventListener(Event.ENTER_FRAME, loop);
		}
		
		private function setVolume(volume:Number):Number
		{
			var vol:Number;
			if (_parent != null) {
				vol = _volume * volume * _parent.volume;
			} else {
				vol = _volume * volume;
			}
			return vol;
		}
		
		private function loop(event:Event):void
		{
			if (_tempLoopData.position >= _tempLoopData.length)
			{
				stop();
				if (repeat) play();
				return void;
			}
			
			if (getTimer() - _startTime >= _tempLoopData.getTime())
			{
				var vol:Number = setVolume(_tempLoopData.getVolume());
				if (vol > 0)
				{	
					dispatchEvent(new Event(TrueLoop.START_PLAYING));
				} else {
					dispatchEvent(new Event(TrueLoop.STOP_PLAYING));
				}
				_tempLoopData.position++;
			}
		}
		
		private function stop(event:Event = null):void
		{
			if (!_playing) return void;
			_playing = false;
			removeEventListener(Event.ENTER_FRAME, loop);
			dispatchEvent(new Event(TrueLoop.STOP_PLAYING));
		}

		public function recorded():void
		{
			_length = _loopData.getTime2(_loopData.length - 1);
			dispatchEvent(new Event(TrueLoop.DATA_REFRESH));
		}
		
		public function addPrimitive(p:Primitive):void
		{
			_primitives.push(p);
		}
		
		/**
		 * Fills the rest of the song with silence or cuts it down.
		 **/	
		public function setLastPoint(length:int):void
		{
			_length = length;
			_loopData.setLast(length);
		}			
			
			
			
		/* SETTERS & GETTERS */

		public function get volume():Number
		{
			return _volume;
		}

		public function set volume(value:Number):void
		{
			if (value < 0)
			{
				trace("VOLUME UNDER 0, FORCING TO 0");
				value = 0;
			}
			_volume = value;
		}

		public function get loopData():LoopData
		{
			return _loopData;
		}

		public function set loopData(value:LoopData):void
		{
			_loopData = value;
		}
		
		public function get isPlaying():Boolean
		{
			return _playing;
		}

		public function get name():String
		{
			return _name;
		}

		public function set name(value:String):void
		{
			_name = value;
			dispatchEvent(new Event(TrueLoop.DATA_REFRESH));
		}

		public function get oneShot():Boolean
		{
			return _oneShot;
		}

		public function set oneShot(value:Boolean):void
		{
			_oneShot = value;
		}

		public function get length():int
		{
			return _length;
		}

		public function set length(value:int):void
		{
			_length = value;
		}

		public function get primitives():Vector.<Primitive>
		{
			return _primitives;
		}

		public function set primitives(value:Vector.<Primitive>):void
		{
			_primitives = value;
		}


	}
}